package cn.chiship.framework.upms.biz.base.service.impl;

import cn.chiship.framework.common.constants.CommonConstants;
import cn.chiship.framework.common.pojo.vo.RedisKeyVo;
import cn.chiship.framework.upms.biz.base.service.IRedisService;
import cn.chiship.sdk.cache.service.RedisService;
import cn.chiship.sdk.core.base.BaseResult;
import cn.chiship.sdk.core.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author lijian
 */
@Service
public class IRedisServiceImpl implements IRedisService {

	@Resource
	RedisService redisService;

	@Autowired
	private RedisTemplate<String, String> redisTemplate;

	@Override
	public BaseResult monitor() {
		Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info());
		Properties commandStats = (Properties) redisTemplate
				.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
		Object dbSize = redisTemplate.execute((RedisCallback<Object>) connection -> connection.dbSize());

		Map<String, Object> result = new HashMap<>(3);
		result.put("info", info);
		result.put("dbSize", dbSize);

		List<Map<String, String>> pieList = new ArrayList<>();
		commandStats.stringPropertyNames().forEach(key -> {
			Map<String, String> data = new HashMap<>(2);
			String property = commandStats.getProperty(key);
			data.put("name", StringUtil.removeStart(key, "cmdstat_"));
			data.put("value", StringUtil.substringBetween(property, "calls=", ",usec"));
			pieList.add(data);
		});
		result.put("commandStats", pieList);
		return BaseResult.ok(result);
	}

	@Override
	public BaseResult keyTrees() {
		Set sortSet = new TreeSet();
		sortSet.addAll(redisService.keys(CommonConstants.COMMON_PROJECT_NAME));
		sortSet.addAll(redisService.keys("AUTH:API_AUTHORIZATION:" + CommonConstants.COMMON_PROJECT_NAME));
		List<RedisKeyVo> redisKeyVos = new ArrayList<>();
		Map<String, TreeSet> map = new HashMap<>(2);
		Iterator iterator = sortSet.iterator();
		while (iterator.hasNext()) {
			String key = iterator.next().toString();
			String[] keys = key.split(":");
			if (keys.length == 1) {
				RedisKeyVo redisKeyVo = new RedisKeyVo();
				redisKeyVo.setKey(key);
				redisKeyVo.setPath(key);
				redisKeyVo.setType(redisTemplate.type(key).code().toLowerCase(Locale.ROOT));
				redisKeyVos.add(redisKeyVo);
			}
			else {
				String tempKey = keys[0];
				TreeSet set;
				if (map.containsKey(tempKey)) {
					set = map.get(tempKey);
					map.put(tempKey, set);
				}
				else {
					set = new TreeSet();
					RedisKeyVo redisKeyVo = new RedisKeyVo();
					redisKeyVo.setKey(tempKey);
					redisKeyVo.setPath(tempKey);
					redisKeyVo.setChildren(new ArrayList<>());
					redisKeyVos.add(redisKeyVo);
				}
				set.add(key.substring(key.indexOf(":") + 1));

				map.put(tempKey, set);
			}
		}

		redisKeyVos = assembleRedisKey(map, redisKeyVos);
		return BaseResult.ok(redisKeyVos);
	}

	public List<RedisKeyVo> assembleRedisKey(Map<String, TreeSet> mapParams, List<RedisKeyVo> redisKeyVosParams) {
		for (Map.Entry<String, TreeSet> entry : mapParams.entrySet()) {
			for (RedisKeyVo keyVo : redisKeyVosParams) {
				if (keyVo.getKey().equals(entry.getKey()) && keyVo.getChildren() != null) {
					TreeSet sortSet = entry.getValue();
					List<RedisKeyVo> redisKeyVos = new ArrayList<>();
					Map<String, TreeSet> map = new HashMap<>(2);
					Iterator iterator = sortSet.iterator();
					while (iterator.hasNext()) {
						String key = iterator.next().toString();
						String[] keys = key.split(":");
						if (keys.length == 1) {
							RedisKeyVo redisKeyVo = new RedisKeyVo();
							redisKeyVo.setKey(key);
							redisKeyVo.setPath(keyVo.getPath() + ":" + key);
							redisKeyVo
									.setType(redisTemplate.type(redisKeyVo.getPath()).code().toLowerCase(Locale.ROOT));

							List<RedisKeyVo> keyVos = keyVo.getChildren();
							keyVos.add(redisKeyVo);
							keyVo.setChildren(keyVos);
						}
						else {
							String tempKey = keys[0];
							TreeSet set;
							if (map.containsKey(tempKey)) {
								set = map.get(tempKey);
								map.put(tempKey, set);
							}
							else {
								set = new TreeSet();
								RedisKeyVo redisKeyVo = new RedisKeyVo();
								redisKeyVo.setKey(keys[0]);
								redisKeyVo.setPath(keyVo.getPath() + ":" + keys[0]);
								redisKeyVo.setChildren(new ArrayList<>());
								List<RedisKeyVo> keyVos = keyVo.getChildren();
								keyVos.add(redisKeyVo);
								keyVo.setChildren(keyVos);
								redisKeyVos.add(redisKeyVo);
							}
							set.add(key.substring(key.indexOf(":") + 1));
							map.put(tempKey, set);
						}
					}
					assembleRedisKey(map, redisKeyVos);
				}
			}
		}
		return redisKeyVosParams;
	}

	@Override
	public BaseResult value(String key) {
		DataType dataType = redisTemplate.type(key);
		if (DataType.STRING.equals(dataType)) {
			return BaseResult.ok(redisService.get(key));
		}
		if (DataType.LIST.equals(dataType)) {
			return BaseResult.ok(redisService.get(key));
		}
		if (DataType.HASH.equals(dataType)) {
			return BaseResult.ok(redisService.hget(key));
		}
		if (DataType.SET.equals(dataType)) {
			return BaseResult.ok(redisService.sGet(key));
		}
		if (DataType.ZSET.equals(dataType)) {
			return BaseResult.ok(redisService.sGet(key));
		}
		return BaseResult.ok(null);
	}

}
